﻿using System.Collections.Generic;
using libZPlay;

namespace Model
{
	public class AudioPlayer
	{
		Dictionary<string, ZPlay> soundsAndPlayers = new Dictionary<string, ZPlay>();
        
        /// <summary>
        /// Вызывает проигрывание однократного звука
        /// </summary>
        /// <param name="soundName">Имя звука</param>
        /// <param name="maxDuration">Максимальная длительность проигрывания</param>
        /// <param name="blockRepeat">Блокировака повторного проигрывания до тех пор, 
        /// пока звук не будет проигран</param>
        /// <param name="volume">Громкость</param>
        /// <param name="frequency">Частота</param>
        /// <param name="soundFileLocation">Звуковой файл</param>
        public void Play(string soundName, uint maxDuration, bool blockRepeat,
            double volume, double frequency, string soundFileLocation)
        {
            if (!SoundExists(soundName))
            {
                ZPlay player = new ZPlay();
                soundsAndPlayers.Add(soundName, player);
                SetSoundFileLocation(soundName, soundFileLocation);
            }

            if (!IsSoundBeingPlayed(soundName))
                if (volume > 0.01)
                {
                    SetVolume(soundName, volume);
                    SetFrequency(soundName, frequency);
                    StartPlaybackOneSound(soundName, maxDuration);
                }
                    /*if (blockRepeat == false)
                    {
                        SetVolume(soundName, volume);
                        SetFrequency(soundName, frequency);
                        StartPlaybackOneSound(soundName, maxDuration);
                    }
                    else //if (IsSoundPaused(soundName) || IsSoundStopped(soundName))
                    {
                        if (IsSoundPaused(soundName))
                        {
                            ResumePlayback(soundName);
                        }
                        else //if (IsSoundStopped(soundName))
                        {
                            SetVolume(soundName, volume);
                            SetFrequency(soundName, frequency);
                            StartPlaybackOneSound(soundName, maxDuration);
                        }
                    }
                     * */
         }

        /// <summary>
        /// Вызывает проигрывание циклического звука
        /// </summary>
        /// <param name="soundName"></param>
        /// <param name="volume"></param>
        /// <param name="frequency"></param>
        /// <param name="echo"></param>
        /// <param name="soundFileLocation"></param>
		public void Play(string soundName, double volume, double frequency,
			bool echo, string soundFileLocation)
		{
			if (!SoundExists(soundName))
			{
				ZPlay player = new ZPlay();
				soundsAndPlayers.Add(soundName, player);
				SetSoundFileLocation(soundName, soundFileLocation);
			}

			SetVolume(soundName, volume);
			SetFrequency(soundName, frequency);
			EnableEcho(soundName, echo);

			if (IsSoundPaused(soundName))
			{
				ResumePlayback(soundName);
			}
			else if (IsSoundStopped(soundName))
			{
				StartPlaybackLoopSound(soundName);
			}
		}

		public void Pause(string soundName)
		{
			PausePlayback(soundName);
		}

		public void Stop(string soundName)
		{
			StopPlayback(soundName);
		}

		private bool SoundNotExists(string soundName)
		{
			return !SoundExists(soundName);
		}

		private bool SoundExists(string soundName)
		{
			return soundsAndPlayers.ContainsKey(soundName);
		}

		public void SetSoundFileLocation(string soundName, string soundFileLocation)
		{
			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.OpenFile(soundFileLocation, TStreamFormat.sfAutodetect);
			}
		}

		public void SetVolume(string soundName, double volume)
		{
			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.SetPlayerVolume((int)volume, (int)volume);
			}
		}

		public void SetFrequency(string soundName, double frequency)
		{
			// libZPlay stop working when frequency is set to about 100
			if (frequency < 99 || frequency > 101)
				return;

			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				
					player.SetRate((int)frequency);
			}
		}
		
		public void EnableEcho(string soundName, bool enable)
		{
			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.EnableEcho(enable);
			}
		}
		
		private ZPlay GetPlayerBySoundName(string soundName)
		{
			return soundsAndPlayers[soundName];
		}

        private void StartPlaybackOneSound(string soundName, uint maxDuration)
        {

                ZPlay player = GetPlayerBySoundName(soundName);
                TStreamTime StartTime = new TStreamTime();
                StartTime.ms = 0;
                TStreamTime EndTime = new TStreamTime();
                TStreamInfo StreamInfo = new TStreamInfo();
                player.GetStreamInfo(ref StreamInfo);
                EndTime.ms = StreamInfo.Length.ms;
                if ( maxDuration < EndTime.ms )
                    EndTime.ms = maxDuration;
                
                player.PlayLoop(TTimeFormat.tfMillisecond, ref StartTime, TTimeFormat.tfMillisecond, ref EndTime, 1, false);
        }

		private void StartPlaybackLoopSound(string soundName)
		{
			if (SoundExists(soundName) &&
				IsSoundStopped(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				TStreamTime StartTime = new TStreamTime();
				StartTime.ms = 1;
				TStreamTime EndTime = new TStreamTime();
				TStreamInfo StreamInfo = new TStreamInfo();
				player.GetStreamInfo(ref StreamInfo);
				EndTime.ms = StreamInfo.Length.ms - 1000;

				player.PlayLoop(TTimeFormat.tfMillisecond, ref StartTime, TTimeFormat.tfMillisecond, ref EndTime, 100000, true);
			}
		}

		private void PausePlayback(string soundName)
		{
			if (SoundExists(soundName) &&
				IsSoundBeingPlayed(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.PausePlayback();
			}
		}

		private void ResumePlayback(string soundName)
		{
			if (SoundExists(soundName) &&
				IsSoundPaused(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.ResumePlayback();
			}
		}
		
		private void StopPlayback(string soundName)
		{
			if (SoundExists(soundName) &&
				(IsSoundBeingPlayed(soundName) ||
				IsSoundPaused(soundName)))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				player.StopPlayback();
			}
		}

		private bool IsSoundStopped(string soundName)
		{
			return !IsSoundBeingPlayed(soundName);
		}

		private bool IsSoundBeingPlayed(string soundName)
		{
			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				TStreamStatus playbackStatus = GetPlaybackStatus(player);
				if (playbackStatus.fPlay)
				{
					return true;
				}
			}
			return false;
		}

		private bool IsSoundPaused(string soundName)
		{
			if (SoundExists(soundName))
			{
				ZPlay player = GetPlayerBySoundName(soundName);
				TStreamStatus playbackStatus = GetPlaybackStatus(player);
				if (playbackStatus.fPause)
				{
					return true;
				}
			}
			return false;
		}

		private TStreamStatus GetPlaybackStatus(ZPlay player)
		{
			TStreamStatus playbackStatus = new TStreamStatus();
			player.GetStatus(ref playbackStatus);
			return playbackStatus;
		}

	}
}
